﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
#endregion // Using Statements

namespace ParticleSystem
{
    /// <summary>
    /// Object describing tweakable particle system settings.
    /// </summary>
    public class ParticleSettings
    {
        #region Fields
        /// <summary>
        /// Name of texture used to render particles.
        /// </summary>
        private String mTextureName = "fire";
        public String textureName
        {
            get { return mTextureName; }
        }

        /// <summary>
        /// The maximum number of particles that this system can hold.
        /// </summary>
        private int mMaxParticles = 100;
        public int maxParticles
        {
            get { return mMaxParticles; }
        }

        /// <summary>
        /// The average number of particles that the system should contain.
        /// </summary>
        private int mAvgCount = 100;
        public int avgCount
        {
            get { return mAvgCount; }
        }

        /// <summary>
        /// The variance allowed in the average number of particles in the system.
        /// </summary>
        private int mCountVariance = 0;
        public int countVariance
        {
            get { return mCountVariance; }
        }

        /// <summary>
        /// The behavior particles should take when they collide with something.
        /// </summary>
        private CollisionBehavior mCollisionBehavior = CollisionBehavior.DIE;
        public CollisionBehavior collisionBehavior
        {
            get { return mCollisionBehavior; }
        }

        /// <summary>
        /// The location of the system's particle emitter.
        /// </summary>
        private Vector3 mEmitterLocation = Vector3.Zero;
        public Vector3 emitterLocation
        {
            get { return mEmitterLocation; }
        }

        /// <summary>
        /// Range of values controlling how much X axis velocity to give each particle.
        /// </summary>
        private Range<float> mHorizontalVelocityRange = new Range<float>(0.0f, 0.0f);
        public Range<float> horizontalVelocityRange
        {
            get { return mHorizontalVelocityRange; }
        }

        /// <summary>
        /// Range of values controlling how much Y axis velocity to give each particle.
        /// </summary>
        private Range<float> mVerticalVelocityRange = new Range<float>(0.0f, 0.0f);
        public Range<float> verticalVelocityRange
        {
            get { return mVerticalVelocityRange; }
        }

        /// <summary>
        /// The range of lifespans of particles in this system.
        /// </summary>
        private Range<TimeSpan> mLifespanRange = new Range<TimeSpan>(TimeSpan.FromSeconds(1.0f), TimeSpan.FromSeconds(1.0f));
        public Range<TimeSpan> lifespanRange
        {
            get { return mLifespanRange; }
        }

        /// <summary>
        /// The start radius range of particles in this system.
        /// </summary>
        private Range<float> mStartRadiusRange = new Range<float>(10.0f, 10.0f);
        public Range<float> startRadiusRange
        {
            get { return mStartRadiusRange; }
        }

        /// <summary>
        /// The end radius range of particles in this system.
        /// </summary>
        private Range<float> mEndRadiusRange = new Range<float>(10.0f, 10.0f);
        public Range<float> endRadiusRange
        {
            get { return mEndRadiusRange; }
        }

        /// <summary>
        /// The range of acceptable colors for particles in this system.
        /// </summary>
        private Range<Color> mColorRange = new Range<Color>(Color.White, Color.White);
        public Range<Color> colorRange
        {
            get { return mColorRange; }
        }

        /// <summary>
        /// Forces specific to partices in this system.
        /// </summary>
        private List<Force> mForces = new List<Force>();
        public List<Force> forces
        {
            get { return mForces; }
        }
        #endregion //Fields

        #region Constructors
        public ParticleSettings()
        {
        }

        public static ParticleSettings ParticleSettingsFromXml(XmlElement settingsElement)
        {
            ParticleSettings settings = new ParticleSettings();

            foreach (XmlElement settingsChildElement in settingsElement)
            {
                // found texture property
                if (settingsChildElement.Name.Equals("texture"))
                {
                    settings.mTextureName = settingsChildElement.ChildNodes[0].Value;
                }
                // found max number of particles property
                else if (settingsChildElement.Name.Equals("maxParticles"))
                {
                    settings.mMaxParticles = int.Parse(settingsChildElement.ChildNodes[0].Value);
                }
                // found average number of particles property
                else if (settingsChildElement.Name.Equals("avgNumParticles"))
                {
                    settings.mAvgCount = int.Parse(settingsChildElement.ChildNodes[0].Value);
                }
                // found variance in particle count property
                else if (settingsChildElement.Name.Equals("varianceNumParticles"))
                {
                    settings.mCountVariance = int.Parse(settingsChildElement.ChildNodes[0].Value);
                }
                // found collision behavior property
                else if (settingsChildElement.Name.Equals("collisionBehavior"))
                {
                    settings.mCollisionBehavior = Utility.CollisionBehaviorFromXml(settingsChildElement);
                }
                // found emitter location property
                else if (settingsChildElement.Name.Equals("emitterLoc"))
                {
                    settings.mEmitterLocation = Utility.Vector3FromXml(settingsChildElement);
                }
                // found horizonal velocity range property
                else if (settingsChildElement.Name.Equals("horizontalVelocity"))
                {
                    settings.mHorizontalVelocityRange = Utility.FloatRangeFromXml(settingsChildElement);
                }
                // found vertical velocity range property
                else if (settingsChildElement.Name.Equals("verticalVelocity"))
                {
                    settings.mVerticalVelocityRange = Utility.FloatRangeFromXml(settingsChildElement);
                }
                // found lifespan range property
                else if (settingsChildElement.Name.Equals("particleLifespan"))
                {
                    Range<float> lifespanFloatRange = Utility.FloatRangeFromXml(settingsChildElement);
                    settings.mLifespanRange = new Range<TimeSpan>(TimeSpan.FromSeconds(lifespanFloatRange.min), TimeSpan.FromSeconds(lifespanFloatRange.max));
                }
                // found start radius range property
                else if (settingsChildElement.Name.Equals("startRadius"))
                {
                    settings.mStartRadiusRange = Utility.FloatRangeFromXml(settingsChildElement);
                }
                // found end radius range property
                else if (settingsChildElement.Name.Equals("endRadius"))
                {
                    settings.mEndRadiusRange = Utility.FloatRangeFromXml(settingsChildElement);
                }
                // found color range property
                else if (settingsChildElement.Name.Equals("color"))
                {
                    settings.mColorRange = Utility.ColorRangeFromXml(settingsChildElement);
                }
                // found particle force
                else if (settingsChildElement.Name.Equals("force"))
                {
                    settings.mForces.Add(Force.ForceFromXml(settingsChildElement));
                }
            }

            return settings;
        }
        #endregion // Constructors
    }
}
